package com.gjy.ioc;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;

/**
 * @author 宫静雨
 * @version 1.0
 * @since 2023-02-07 09:21:08
 */
@UnitScan(value = "com.gjy.ioc")
public class IocHandler {

    private static final String OS_NAME = System.getProperty("os.name");
    public static final Map<String, Object> MAP = new ConcurrentHashMap<>();

    /**
     * 标识类,携带 @UnitScan 注解,自动注册包下含有 @Unit 注解的类
     *
     * @param clazz 标识类
     * @param <T>   泛型
     */
    public static <T> void handler(Class<T> clazz) throws IOException {
        if (clazz.isAnnotationPresent(UnitScan.class)) {
            UnitScan unitScan = clazz.getDeclaredAnnotation(UnitScan.class);
            // 包名
            String v = unitScan.value();
            String path = v.replaceAll("\\.", Matcher.quoteReplacement(File.separator));

            String s = new File(path).getAbsolutePath().split(v)[0] + "src/main/java/" + path;
            List<String> list = scanFiles(s);
            list.stream()
                    .map(c -> {
                        try {
                            return clazz.getClassLoader().loadClass(c);
                        } catch (ClassNotFoundException e) {
                            System.out.println("e.getMessage() = " + e.getMessage());
                            return null;
                        }
                    }).filter(Objects::nonNull)
                    .filter(c -> c.isAnnotationPresent(Unit.class))
                    .forEach(c -> {
                        Unit unit = c.getDeclaredAnnotation(Unit.class);
                        try {
                            if (unit.value().equals("")) {
                                String simpleName = c.getSimpleName();
                                MAP.put(simpleName, c.newInstance());
                            } else {
                                MAP.put(unit.value(), c.newInstance());
                            }
                        } catch (Exception e) {
                            System.out.println("e.getMessage() = " + e.getMessage());
                        }
                    });
        }

    }

    public static void validate(Field field) {
        if (field.isAnnotationPresent(Resource.class)) {
            String fieldName = field.getName();
        }
    }

    private static List<String> scanFiles(String file) throws IOException {
        List<String> list = new ArrayList<>();
        Files.walkFileTree(Paths.get(file), new FileVisitor<Path>() {
            //访问文件夹之前自动调用此方法
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                return FileVisitResult.CONTINUE;
            }

            //访问文件时自动调用此方法
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                String s;
                if (OS_NAME.contains("Windows")) {
                    s = file.toString().split("src" + File.separator + File.separator + "main" + File.separator + File.separator + "java")[1]
                            .split("\\.")[0];
                } else { // Linux&Other
                    s = file.toString().split("src" + File.separator + "main" + File.separator + "java")[1]
                            .split("\\.")[0];
                }
                String clazzName;
                if (OS_NAME.contains("Windows")) {
                    clazzName = s.substring(1).replaceAll(File.separator + File.separator, "\\.");
                } else { // Linux&Other
                    clazzName = s.substring(1).replaceAll(File.separator, "\\.");
                }
                list.add(clazzName);
                return FileVisitResult.CONTINUE;
            }

            //访问文件失败时自动调用此方法
            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                System.out.println("exc.getMessage() = " + exc.getMessage());
                return FileVisitResult.CONTINUE;
            }

            //访问文件夹之后自动调用此方法
            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }
        });
        return list;
    }
}
